using System;
using FishFillets.GameComponents;
using FishFillets.GameComponents.Helpers;
using FishFillets.Model;
using FishFillets.Model.GameItems;
using FishFillets.ObjectLogic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;

namespace FishFillets.WP7.XNA
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Game, IGameView
    {
        private readonly GraphicsDeviceManager graphics;
        private GameController gameController;

        private PanelComponent panelComponent;
        private MapComponent mapComponent;
        private LevelComponent levelComponent;
        private SoundEffectComponent soundComponent;
        private DialogComponent dialogComponent;
        private MusicComponent musicComponent;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);

            // Extend battery life under lock.
            InactiveSleepTime = TimeSpan.FromSeconds(1);

            graphics.IsFullScreen = true;
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 480;

            // Enable gestures
            TouchPanel.EnabledGestures = GestureType.Tap |
                                         GestureType.FreeDrag |
                                         GestureType.DragComplete;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Initialize helper classes
            LineBatch.Init(GraphicsDevice);

            // create panel component
            panelComponent = new PanelComponent(this, graphics);
            Components.Add(panelComponent);

            // create music component
            musicComponent = new MusicComponent(this, Content);
            Components.Add(musicComponent);

            // create the main game controller
            gameController = new GameController(this);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                if (levelComponent != null)
                {
                    GameController.Instance.AbortLevel();
                }
                else
                {
                    GameController.Instance.ExitGame();
                    Exit();
                }
            }

            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample gesture = TouchPanel.ReadGesture();
                Vector2 pos = gesture.Position;

                switch (gesture.GestureType)
                {
                    case GestureType.Tap:
                        HandleTapGesture(pos, gameTime);
                        break;
                    case GestureType.FreeDrag:
                        HandleFreeDragGesture(pos);
                        break;
                    case GestureType.DragComplete:
                        isDrag = false;
                        break;
                }
            }
            
            base.Update(gameTime);
        }

        private int xstart;
        private int ystart;
        private bool isDrag;

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);
        }

        public void ShowMap(Map map)
        {
            // create map game component
            mapComponent = new MapComponent(this, map);
            Components.Add(mapComponent);
            GameController.Instance.MusicTrack = "music/menu";
        }

        public void HideMap()
        {
            Components.Remove(mapComponent);
            mapComponent = null;
        }

        public void ShowLevel(Level level)
        {
            // create level component
            levelComponent = new LevelComponent(this, level);
            Components.Add(levelComponent);
            soundComponent = new SoundEffectComponent(this, Content);
            Components.Add(soundComponent);
            dialogComponent = new DialogComponent(this, gameController.dialogManager);
            Components.Add(dialogComponent);
        }

        public void HideLevel()
        {
            Components.Remove(levelComponent);
            levelComponent = null;
            Components.Remove(soundComponent);
            soundComponent = null;
            Components.Remove(dialogComponent);
            dialogComponent = null;
        }

        #region ----- Gesture handlers -----------------------------------

        private void HandleTapGesture(Vector2 pos, GameTime gameTime)
        {
            if (levelComponent != null)
            {
                // if level is active, try to select fish under tap
                Fish fish = SelectHelper.TrySelectFish(levelComponent.Level, (int) pos.X, (int) pos.Y);
                if (fish != null)
                {
                    GameController.Instance.SelectPlayer(fish);
                    return;
                }
            }
            else
            {
                // if map is active, try to open level under tap
                LevelRef levelRef = SelectHelper.TrySelectLevelRef(GameController.Instance.Map, (int) pos.X, (int) pos.Y);

                // if level button was clicked
                if (levelRef != null)
                {
                    GameController.Instance.LoadLevel(levelRef);
                    return;
                }
            }

            // check if any button was tapped
            panelComponent.TryClickButton((int)pos.X, (int)pos.Y, gameTime);
        }

        private void HandleFreeDragGesture(Vector2 pos)
        {
            // Continue to move a dragged card
            if (isDrag)
            {
                bool moved = false;
                int xpos = (int)pos.X / Common.BlockWidth;
                int ypos = (int)pos.Y / Common.BlockHeight;
                if (xpos == xstart)
                {
                    if (ypos > ystart)
                    {
                        moved = GameController.Instance.Move(Direction.Down);
                    }
                    else if (ypos < ystart)
                    {
                        moved = GameController.Instance.Move(Direction.Up);
                    }
                }
                else if (xpos > xstart)
                {
                    moved = GameController.Instance.Move(Direction.Right);
                }
                else if (xpos < xstart)
                {
                    moved = GameController.Instance.Move(Direction.Left);
                }
                if (moved)
                {
                    ystart = ypos;
                    xstart = xpos;
                }
            }
            // Try to select fish
            else if (levelComponent != null)
            {
                Fish fish = SelectHelper.TrySelectFish(levelComponent.Level, (int)pos.X, (int)pos.Y);
                GameController.Instance.SelectPlayer(fish);
                if (fish != null)
                {
                    xstart = (int)pos.X / Common.BlockWidth;
                    ystart = (int)pos.Y / Common.BlockHeight;
                    isDrag = true;
                }
            }
        }

        #endregion
    }
}
